package com.shrcl.engineerprocess.domain.impl;

import com.google.common.base.Objects;
import com.shrcl.engineerprocess.domain.Engineer;
import com.shrcl.engineerprocess.domain.EngineerLevel;
import com.shrcl.engineerprocess.domain.EngineerMonthlyCost;
import com.shrcl.engineerprocess.domain.EngineerMonthlyCostStatus;
import com.shrcl.engineerprocess.domain.events.EngineerMonthlyCostEventsManager;
import com.shrcl.engineerprocess.domain.impl.EngineerImpl;
import com.shrcl.engineerprocess.domain.impl.EngineerLevelImpl;
import com.shrcl.engineerprocess.domain.proxy.EngineerMonthlyCostProxy;
import com.uniquesoft.uidl.validation.Validates;
import edu.fudan.langlab.domain.statemachine.ModelObjectLogService;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IObjectFactory;
import edu.fudan.mylang.utils.DateUtil;
import edu.fudan.mylang.utils.DateUtil.Month;
import java.util.Collection;
import java.util.Date;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;
import org.springframework.beans.factory.BeanFactory;

@Entity
@DiscriminatorValue("ENGINEERMONTHLYCOST_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "engineermonthlycost")
public class EngineerMonthlyCostImpl extends BaseModelObject implements EngineerMonthlyCost {
  public EngineerMonthlyCostImpl() {
    super();
  }
  
  public EngineerMonthlyCostImpl(final Engineer engineer) {
    super();
    this.engineer = engineer;
  }
  
  private EngineerMonthlyCostStatus Status;
  
  public EngineerMonthlyCostStatus getStatus() {
    return this.Status;
  }
  
  private ModelObjectLogService getModelObjectLogService() {
    return getBeanFactory().getBean(ModelObjectLogService.class);
  }
  
  private void _start() {
    
    this.checkValid();
    Status=EngineerMonthlyCostStatus.created;
  }
  
  public void start() {
    if(Status==null){
    	_start();
    	getModelObjectLogService().createLog(this,"Status","Start");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerMonthlyCostEventsManager.class).fireStarted(this);					
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException("allready started");
    }
  }
  
  private void _updateCost(final Procedure1<? super EngineerMonthlyCost> updater) {
    
    updater.apply(this);
    BeanFactory _beanFactory = this.getBeanFactory();
    EngineerMonthlyCostEventsManager _bean = _beanFactory.<EngineerMonthlyCostEventsManager>getBean(EngineerMonthlyCostEventsManager.class);
    _bean.fireEngineerMonthlyCostUpdate(this);
  }
  
  public void updateCost(final Procedure1<? super EngineerMonthlyCost> updater) {
    if(Status==EngineerMonthlyCostStatus.created){
    	_updateCost(updater);
    	getModelObjectLogService().createLog(this,"Status","updateCost");
    	getBeanFactory().getBean(com.shrcl.engineerprocess.domain.events.EngineerMonthlyCostEventsManager.class).fireUpdateCost(this,updater);						
    }else{
    	throw new edu.fudan.langlab.domain.statemachine.InvalidStateException(Status.name());
    }
  }
  
  public Boolean isCreated() {
    return com.shrcl.engineerprocess.domain.EngineerMonthlyCostStatus.created==Status;
  }
  
  @ManyToMany(targetEntity = EngineerLevelImpl.class)
  @JoinTable(name = "m2m_engineermonthlycost_levels", joinColumns = @JoinColumn(name = "engineermonthlycost_id") , inverseJoinColumns = @JoinColumn(name = "engineerLevel_inv_id") )
  private Collection<EngineerLevel> levels = new java.util.ArrayList<com.shrcl.engineerprocess.domain.EngineerLevel>();;
  
  public Collection<EngineerLevel> getLevels() {
    return this.levels;
  }
  
  public EngineerMonthlyCost setLevels(final Iterable<EngineerLevel> levels) {
    removeAllLevels();
    for(EngineerLevel ca : levels){
    	addtoLevels(ca);
    }
    return this;		
    
  }
  
  public EngineerMonthlyCost addtoLevels(final EngineerLevel engineerLevel) {
    this.levels.add(engineerLevel);
    return this;
    
  }
  
  public EngineerMonthlyCost removeAllLevels() {
    this.levels.clear();
    return this;	
    
  }
  
  public EngineerMonthlyCost removeFromLevels(final EngineerLevel engineerLevel) {
    this.levels.remove(engineerLevel);
    return this;
    
  }
  
  @JoinColumn(name = "engineer_id")
  @ManyToOne(targetEntity = EngineerImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private Engineer engineer;
  
  public Engineer getEngineer() {
    return this.engineer;
  }
  
  public EngineerMonthlyCost setEngineer(final Engineer engineer) {
    this.engineer = engineer;
    return this;			
    
  }
  
  private Date month;
  
  public Date getMonth() {
    return this.month;
  }
  
  public EngineerMonthlyCost setMonth(final Date month) {
    this.month = month;
    return this;			
    
  }
  
  private Double cost;
  
  public Double getCost() {
    return this.cost;
  }
  
  public EngineerMonthlyCost setCost(final Double cost) {
    this.cost = cost;
    return this;			
    
  }
  
  public String getMonthStr() {
    Month _month = DateUtil.getMonth(this.month);
    String _serialize = _month.serialize();
    return _serialize;
  }
  
  public void checkValid() {
    boolean _notEquals = (!Objects.equal(this.engineer, null));
    Validates.Assert(_notEquals, "\u5DE5\u7A0B\u5E08\u4E0D\u80FD\u4E3A\u7A7A");
    Boolean _monthCostExisting = this.engineer.monthCostExisting(this.month);
    boolean _not = (!_monthCostExisting);
    Validates.Assert(_not, "\u6708\u5EA6\u5DF2\u7ECF\u5B58\u5728");
  }
  
  public static EngineerMonthlyCost create(final Engineer engineer, final IObjectFactory objectFactory) {
    com.shrcl.engineerprocess.domain.EngineerMonthlyCost engineerMonthlyCost = new com.shrcl.engineerprocess.domain.impl.EngineerMonthlyCostImpl(
    	engineer
    );
    objectFactory.create(engineerMonthlyCost);
    return engineerMonthlyCost;			
    
  }
  
  public static EngineerMonthlyCost createEngineerMonthlyCostImpl(final Engineer engineer, final IObjectFactory objectFactory, final Procedure1<EngineerMonthlyCost> init) {
    com.shrcl.engineerprocess.domain.EngineerMonthlyCost engineerMonthlyCost = new com.shrcl.engineerprocess.domain.impl.EngineerMonthlyCostImpl(
    	engineer
    );
    objectFactory.create(engineerMonthlyCost);
    init.apply(engineerMonthlyCost);
    
    return engineerMonthlyCost;			
    
  }
  
  public EngineerMonthlyCostProxy toProxy() {
    com.shrcl.engineerprocess.domain.proxy.EngineerMonthlyCostProxy proxy = new com.shrcl.engineerprocess.domain.proxy.EngineerMonthlyCostProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    proxy.setStatus(this.getStatus().name());
    return proxy;
    
  }
}
